/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "border_option_napi.h"
#include "napi_parser.h"
#include "log.h"

namespace ImageKnifePro {
BorderOptionNapi::BorderOptionNapi(napi_env env, napi_value &value)
{
    napi_value width = NapiParser::ParseProperty(env, value, "width");
    if (width != nullptr) {
        ParseWidth(env, width);
    }

    napi_value color = NapiParser::ParseProperty(env, value, "color");
    if (color != nullptr) {
        ParseColor(env, color);
    }

    napi_value radius = NapiParser::ParseProperty(env, value, "radius");
    if (radius != nullptr) {
        ParseRadius(env, radius);
    }

    napi_value style = NapiParser::ParseProperty(env, value, "style");
    if (style != nullptr) {
        ParseStyle(env, style);
    }
}

void BorderOptionNapi::ParseWidth(napi_env env, napi_value &value)
{
    bool hasProperty = false;
    bool typeMatched = false;
    napi_status status;

    // LocalizedEdgeWidths
    std::vector<std::string> names = {"top", "end", "bottom", "start"};
    const int namesSize = 4;
    for (int i = 0; i < namesSize; i++) {
        napi_value lengthMetrics;
        status = napi_has_named_property(env, value, names[i].c_str(), &hasProperty);
        if (status == napi_ok && hasProperty) {
            napi_get_named_property(env, value, names[i].c_str(), &lengthMetrics);
            status = napi_has_named_property(env, lengthMetrics, "value", &hasProperty);
            if (status == napi_ok && hasProperty) {
                typeMatched = true;
            }
        }
    }

    if (typeMatched) {
        IMAGE_KNIFE_LOG(LOG_WARN, "Border width only support number for now");
        return;
    }

    // EdgeWidths
    width = {0, 0, 0, 0};
    names = {"top", "right", "bottom", "left"};
    for (int i = 0; i < namesSize; i++) {
        napi_value length;
        status = napi_has_named_property(env, value, names[i].c_str(), &hasProperty);
        if (status == napi_ok && hasProperty) {
            typeMatched = true;
            napi_get_named_property(env, value, names[i].c_str(), &length);
            width[i] = ParseLength(env, length);
        }
    }

    // Length for four edge
    if (!typeMatched) {
        width = {ParseLength(env, value)};
    }
}

void BorderOptionNapi::ParseRadius(napi_env env, napi_value &value)
{
    bool hasProperty = false;
    bool typeMatched = false;
    napi_status status;

    std::vector<std::string> names = {"topLeft", "topRight", "bottomLeft", "bottomRight"};
    const int namesSize = 4;
    radius = {0, 0, 0, 0};
    for (int i = 0; i < namesSize; i++) {
        napi_value lengthValue;
        status = napi_has_named_property(env, value, names[i].c_str(), &hasProperty);
        if (status == napi_ok && hasProperty) {
            typeMatched = true;
            napi_get_named_property(env, value, names[i].c_str(), &lengthValue);
            // LocalizedBorderRadiuses
            status = napi_has_named_property(env, lengthValue, "value", &hasProperty);
            if (status == napi_ok && hasProperty) {
                IMAGE_KNIFE_LOG(LOG_WARN, "Border radius only support number for now");
            } else { //  BorderRadiuses
                radius[i] = ParseLength(env, lengthValue);
            }
        }
    }

    if (!typeMatched) {
        radius = {ParseLength(env, value)};
    }
}

void BorderOptionNapi::ParseColor(napi_env env, napi_value &value)
{
    bool hasProperty = false;
    bool typeMatched = false;
    napi_status status;

    const uint32_t blackColor = 0xFF000000;
    
    // LocalizedEdgeColors |  EdgeColors
    napi_value resourceColor;
    color = {0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000};
    std::vector<std::string> names = {"top", "end", "bottom", "start"};
    const int namesSize = 4;
    for (int i = 0; i < namesSize; i++) {
        status = napi_has_named_property(env, value, names[i].c_str(), &hasProperty);
        if (status == napi_ok && hasProperty) {
            typeMatched = true;
            napi_get_named_property(env, value, names[i].c_str(), &resourceColor);
            color[i] = ParseResourceColor(env, resourceColor);
        }
    }

    status = napi_has_named_property(env, value, "right", &hasProperty);
    if (status == napi_ok && hasProperty) {
        typeMatched = true;
        napi_get_named_property(env, value, "right", &resourceColor);
        color[1] = ParseResourceColor(env, resourceColor);
    }

    status = napi_has_named_property(env, value, "left", &hasProperty);
    const int colorLeftIndex = 3;
    if (status == napi_ok && hasProperty) {
        typeMatched = true;
        napi_get_named_property(env, value, "left", &resourceColor);
        color[colorLeftIndex] = ParseResourceColor(env, resourceColor);
    }

    // ResourceColor
    if (!typeMatched) {
        color = {ParseResourceColor(env, value)};
    }
}

void BorderOptionNapi::ParseStyle(napi_env env, napi_value &value)
{
    bool hasProperty = false;
    bool typeMatched = false;
    napi_status status;

    // EdgeStyles
    napi_value styleValue;
    std::vector<std::string> names = {"top", "right", "bottom", "left"};
    ArkUI_BorderStyle defaultStyle = ARKUI_BORDER_STYLE_SOLID;
    style = {defaultStyle, defaultStyle, defaultStyle, defaultStyle};
    const int namesSize = 4;
    for (int i = 0; i < namesSize; i++) {
        status = napi_has_named_property(env, value, names[i].c_str(), &hasProperty);
        if (status == napi_ok && hasProperty) {
            typeMatched = true;
            napi_get_named_property(env, value, names[i].c_str(), &styleValue);
            style[i] = parseBorderStyle(env, styleValue);
        }
    }

    if (!typeMatched) {
        style = {parseBorderStyle(env, value)};
    }
}

float BorderOptionNapi::ParseLength(napi_env env, napi_value &value)
{
    // string | number | Resource
    napi_valuetype type;
    if (napi_typeof(env, value, &type) == napi_ok && type == napi_string) {
        // 需要解析百分比Length
        IMAGE_KNIFE_LOG(LOG_WARN, "BorderWidth/Radius only support number for now");
        return 0;
    } else if (napi_typeof(env, value, &type) == napi_ok && type == napi_number) {
        return NapiParser::ParseFloat(env, value);
    } else {
        IMAGE_KNIFE_LOG(LOG_WARN, "BorderWidth/Radius only support number for now");
        return 0;
    }
}

uint32_t HexStringToUint32(const std::string &str)
{
    const uint32_t blackColor = 0xFF000000;
    const size_t hex = 16;
    try {
        return static_cast<uint32_t>(std::stoul(str, nullptr, hex));
    } catch (std::exception err) {
        IMAGE_KNIFE_LOG(LOG_ERROR, "BorderColor Hex String To Uint32 Error:%{public}s, %{public}s",
                        err.what(), str.c_str());
    }
    return blackColor;
}

uint32_t BorderOptionNapi::ParseResourceColor(napi_env env, napi_value &value)
{
    const uint32_t blackColor = 0xFF000000;
    const size_t rgbFormatLength = 7;
    const size_t argbFormatLength = 9;

    napi_valuetype type;
    napi_typeof(env, value, &type);

    if (type == napi_string) {
        // Color.white 等枚举类型已转成string类型
        // "#FF0000FF" string类型 包含ARGB和RGB类型
        std::string colorString = NapiParser::ParseString(env, value);
        IMAGE_KNIFE_CHECK_RETURN(colorString.size() < rgbFormatLength, blackColor, "Border Color String Length Error");
        if (colorString.size() == rgbFormatLength) {
            // RGB格式设置默认alpha通道
            return HexStringToUint32(colorString.substr(1, rgbFormatLength - 1)) | blackColor;
        }
        IMAGE_KNIFE_CHECK_RETURN(colorString.size() < argbFormatLength, blackColor,
                                 "Border Color ARGB Format String Length Error");
        return HexStringToUint32(colorString.substr(1, argbFormatLength - 1));
    } else if (type == napi_number) {
        // ArkTs的number类型格式为RGB, 设置默认alpha通道
        return NapiParser::ParseUint32(env, value) | blackColor;
    }
    return blackColor;
}

ArkUI_BorderStyle BorderOptionNapi::parseBorderStyle(napi_env env, napi_value &value)
{
    // C: ARKUI_BORDER_STYLE_SOLID = 0, ARKUI_BORDER_STYLE_DASHED, ARKUI_BORDER_STYLE_DOTTED
    // JS: Dotted = 2, Dashed = 1, Solid = 0

    return static_cast<ArkUI_BorderStyle>(NapiParser::ParseInt(env, value));
}
}